window.GS = window.GS || {}, function(a, b){
    _.extend(Backbone.View.prototype, {
        getSpinner: function(){
            return this.$(".spinner")
        }
    }), _.mixin({
        defined: function(a){
            return a !== b && a !== null
        },
        orEqual: function(a, b){
            return this.defined(a) ? a : b
        },
        UUID: function(){
            return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(a){
                var b = Math.random() * 16 | 0, c = a == "x" ? b : b & 3 | 8;
                return c.toString(16)
            }).toUpperCase()
        },
        getTemplate: function(a){
            var b = document.getElementById(a);
            if (b) 
                return $(b).html();
            throw new Error("Can't find view " + a)
        },
        compile: function(a){
            var b = this.getTemplate(a);
            return _.template(b)
        },
        prettyDuration: function(a){
            var b = ~ ~ (a / 60), c = ~ ~ a - b * 60;
            return [b < 10 ? "0" + b : b, c < 10 ? "0" + c : c].join(":")
        },
        truncate: function(a, b){
            return a.length > b ? a.slice(0, b) + "&hellip;" : a
        }
    })
}(this), function(a, b){
    function d(){
        this.requests = [], this.pendingRequest = null
    }
    function e(a, b, c, d, e){
        function g(a){
            f.isPending = !1, f.lastResolution = (new Date).valueOf()
        }
        this.method = _.orEqual(a, ""), this.parameters = _.orEqual(b, {}), this.options = _.orEqual(c, {}), this.useHTTPS = _.orEqual(d, !1), this.useSWF = !1, this.type = "normal", this.failedAuth = !1, this.isPending = !1, this.numRetries = 0, this.lastFault = null, this.lastResolution = 0, this.successFilters = [], this.faultFilters = [], this._dfd = _.Deferred();
        var f = this;
        this.promise().always(g)
    }
    function f(){
        var a = "";
        for (var b = 0; b < 6; b++) 
            a += Math.floor(Math.random() * 16).toString(16);
        return a != c.lastRandomizer ? a : f()
    }
    function g(a){
        a = _.orEqual(a, {});
        var b = {
            client: c.client,
            clientRevision: c.clientRevision,
            privacy: c.privacy,
            country: c.country,
            uuid: c.uuID
        };
        return c.sessionID && (b.session = c.sessionID), _.extend(b, a)
    }
    function h(a, b){
        _.defined(a) || (a = {
            fault: {
                message: "Empty Result",
                code: c.faultCodes.EMPTY_RESULT
            }
        }), a.header && i(a.header), a.fault ? j(a, b) : b.resolve(_.orEqual(a.result, a))
    }
    function i(a){
        var b = a.session;
        b && b != c.sessionID && (c.sessionID = b, c.tokenPending = !1, k()), a.expiredClient && (c.clientExpired = !0, alert("Invalid Client"))
    }
    function j(a, b){
        if (a && _.defined(a.code)) {
            console.log("HANDLE FAULT CODE", a.code, b.method);
            if (a.code == c.faultCodes.INVALID_TOKEN) {
                var d = (new Date).valueOf();
                if ((!c.lastTokenFailed || d - c.lastTokenFailed >= 3e5) && b.numRetries === 0) {
                    c.lastTokenFailed = !1, b.isPending = !1, b.numRetries++, c.callsPendingToken.push(b), k();
                    return
                }
            }
            else {
                if (a.code == c.faultCodes.HTTP_TIMEOUT || a.code == c.faultCodes.EMPTY_RESULT) {
                    b.lastFault = a, b.retry(100 + b.numRetries * 100);
                    return
                }
                a.code != c.faultCodes.MAINTENANCE && (a.code == c.faultCodes.INVALID_CLIENT ? alert("Invalid Client") : a.code == c.faultCodes.INVALID_SESSION && alert("Session bad"))
            }
        }
        b.reject(a)
    }
    function k(){
        var a, b;
        if (c.tokenPending) 
            return;
        l(), c.tokenPending = !0, c.sessionID ? (a = hex_md5(c.sessionID), b = e.createRequest(!1, "getCommunicationToken", {
            secretKey: a
        }, {}, !0), b.promise().then(m, function(a){
            n(a, b)
        }), b.send()) : (b = e.createRequest(!1, "initiateSession"), b.send())
    }
    function l(){
        c.currentToken = null, c.tokenExpires = 0
    }
    function m(a){
        var b = new Date;
        c.lastTokenFailed = !1, c.currentToken = a, c.tokenPending = !1, c.tokenExpires = 15e5 + b.valueOf();
        var d;
        while (c.callsPendingToken.length) 
            d = c.callsPendingToken.shift(), d.send()
    }
    function n(a, b){
        var d = new Date;
        c.tokenPending = !1, c.lastTokenFailed = d.valueOf();
        var e;
        while (c.callsPendingToken.length) 
            e = c.callsPendingToken.shift(), e.reject({
                message: "SERVICE_CREATE_TOKEN_FAIL",
                code: c.faultCodes.INVALID_TOKEN
            })
    }
    var c = {
        faultCodes: {
            INVALID_CLIENT: 1024,
            RATE_LIMITED: 512,
            INVALID_TOKEN: 256,
            INVALID_SESSION: 16,
            MAINTENANCE: 10,
            MUST_BE_LOGGED_IN: 8,
            HTTP_TIMEOUT: 6,
            PARSE_ERROR: 4,
            HTTP_ERROR: 2,
            EMPTY_RESULT: -256
        },
        headers: {
            client: "mobileshark",
            clientRevision: "20120112"
        },
        revToken: "boomGoesTheDolphin",
        defaultEndpoint: "more.php",
        uuID: _.UUID(),
        country: {
            ID: "1",
            CC1: "0",
            CC2: "0",
            CC3: "0",
            CC4: "0",
            IPR: "1"
        },
        sessionID: null,
        privacy: 0,
        currentToken: null,
        tokenExpires: 0,
        tokenPending: !1,
        lastTokenFailed: !1,
        lastRandomizer: null,
        downForMaintenance: !1,
        lastDowntimeNotification: 0,
        clientExpired: !1,
        callsPendingToken: []
    };
    d.prototype.queue = function(a){
        function b(){
            if (this.requests.length) {
                this.pendingRequest = this.requests.shift();
                var a = this, c = function(){
                    a.pendingRequest = null, b.call(a)
                };
                this.pendingRequest.promise().always(c), this.pendingRequest.send()
            }
        }
        this.requests.push(a), this.pendingRequest || b.call(this)
    }, e.createRequest = function(a){
        var b = [].slice.call(arguments, 1), c = (new Date).valueOf(), d = new this;
        this.apply(d, b);
        if (a) {
            var e = d.getCacheKey(), f = d.pendingCallCache[e];
            _.defined(f) && (!f.isResolved() || c - f.lastResolution < 6e5) ? d = f : d.pendingCallCache[e] = d
        }
        return d
    }, e.prototype.promise = function(){
        return this._dfd.promise()
    }, e.prototype.isResolved = function(){
        return this._dfd.isResolved()
    }, e.prototype.isRejected = function(){
        return this._dfd.isRejected()
    }, e.prototype.resolve = function(a){
        for (var b = 0; b < this.successFilters.length; b++) 
            _.isFunction(this.successFilters[b]) && (a = this.successFilters[b](a));
        this.lastResolution = (new Date).valueOf(), this._dfd.resolve(a)
    }, e.prototype.resolveWith = function(a, b){
        for (var c = 0; c < this.successFilters.length; c++) 
            _.isFunction(this.successFilters[c]) && (b = this.successFilters[c](b));
        this.lastResolution = (new Date).valueOf(), this._dfd.resolveWith(a, b)
    }, e.prototype.reject = function(a){
        for (var b = 0; b < this.faultFilters.length; b++) 
            _.isFunction(this.faultFilters[b]) && (a = this.faultFilters[b](a));
        this._dfd.reject(a)
    }, e.prototype.rejectWith = function(a, b){
        for (var c = 0; c < this.faultFilters.length; c++) 
            _.isFunction(this.faultFilters[c]) && (b = this.faultFilters[c](b));
        this._dfd.rejectWith(a, b)
    }, e.prototype.pendingCallCache = [], e.prototype.cacheKeyProps = ["method", "parameters", "type"], e.prototype.getCacheKey = function(){
        var a, b, c = "";
        for (a in this.cacheKeyProps) 
            this.cacheKeyProps.hasOwnProperty(a) && (b = this[this.cacheKeyProps[a]], b instanceof String ? c += b : c += JSON.stringify(b));
        return hex_md5(c)
    }, e.prototype.send = function(b){
        b && b.length == 2 && this.promise().then(b[0], b[1]);
        var d = this, e = !0, i = (new Date).valueOf();
        if (this.isPending || this.isResolved()) 
            return;
        if (c.clientExpired) {
            this.reject({
                message: "POPUP_INVALID_CLIENT_MSG",
                code: c.faultCodes.INVALID_CLIENT
            });
            return
        }
        this.isPending = !0;
        if (this.numRetries >= 3) {
            this.reject(this.lastFault);
            return
        }
        this.numRetries > 0 && (e = !1);
        if (this.type == "facebook" || this.type == "lastfm") 
            return;
        if (c.tokenExpires > i || ["getCommunicationToken", "initiateSession", "getServiceStatus"].indexOf(this.method) != -1) {
            if (c.downForMaintenance && this.method != "getServiceStatus") {
                this.reject({
                    message: "SERVICE_DOWN_MAINTENANCE",
                    code: c.faultCodes.MAINTENANCE
                });
                return
            }
            var l = {}, m = "/" + c.defaultEndpoint + "?" + this.method;
            this.useHTTPS && (m = "https://" + a.location.host + m), l.header = g(c.headers), l.method = this.method, l.parameters = this.parameters, this.method == "getStreamKeyFromSongIDEx" && (l.parameters.country = l.header.country);
            if (c.currentToken) {
                var n;
                c.lastRandomizer = f(), n = hex_sha1([this.method, c.currentToken, c.revToken, c.lastRandomizer].join(":")), l.header.token = c.lastRandomizer + n
            }
            $.ajax(_.extend({}, this.options, {
                contentType: "text/plain",
                dataType: "json",
                type: "POST",
                data: JSON.stringify(l),
                cache: e,
                url: m,
                success: function(a, b, c){
                    h(a, d)
                },
                error: function(a, b, e){
                    var f = {};
                    switch (b) {
                        case "parsererror":
                            f.code = c.faultCodes.PARSE_ERROR, f.message = "SERVICE_PARSE_JSON";
                            break;
                        case "timeout":
                            f.code = c.faultCodes.HTTP_TIMEOUT, f.message = "SERVICE_REQUEST_TIMEOUT";
                            break;
                        case "error":
                        case "notmodified":
                        default:
                            f.code = c.faultCodes.HTTP_ERROR, f.message = "SERVICE_HTTP_ERROR"
                    }
                    j(f, d)
                }
            }))
        }
        else 
            this.isPending = !1, c.callsPendingToken.push(this), k()
    }, e.prototype.retry = function(a){
        var b = this;
        this.isPending = !1, this.numRetries++, _.wait(a).then(function(){
            b.send()
        })
    }, e.prototype.queue = function(a){
        _.defined(e.prototype.queues) || (e.prototype.queues = {});
        var b = e.prototype.queues[a];
        _.defined(b) || (b = e.prototype.queues[a] = new d), b.queue(this)
    }, a.Backbone.sync = function(a, b, c){
        var d, f, g = b.url(a);
        return d = e.createRequest(!1, g, c.parameters || {}, {}), f = d.promise(), f.then(c.success, c.error), d.send(), f
    }, a.GS.config && a.GS.config.sessionID && (c.sessionID = a.GS.config.sessionID), a.GS.config && a.GS.config.country && (c.country = a.GS.config.country)
}(this), window.GS.models = window.GS.models || {}, function(a, b){
    function e(b, c){
        var d, e = "http://" + a.location.hostname + ":8081/stream.php";
        return d = b.match(/(.+?)\./)[1], e + "?" + [["server", d], ["streamKey", c]].map(function(a){
            return a.join("=")
        }).join("&")
    }
    function f(a, b){
        return GS.config.runMode != "production" && (a = "staging." + a), "http://" + a + "/stream.php?streamKey=" + b
    }
    var c = Backbone.Model.extend({
        initialize: function(a){
            this.id = a.SongID, this.attributes.coverURL = c.cover + (this.attributes.CoverArtFilename || "album.png"), this.attributes.name = this.attributes.Name || this.attributes.SongName
        },
        stream: function(){
            return this._stream || (this._stream = new g({
                id: this.id
            })), this._stream
        }
    }, {
        cover: "http://images.grooveshark.com/static/albums/50_"
    }), d = Backbone.Collection.extend({
        model: c
    }), g = Backbone.Model.extend({
        initialize: function(a){
            this.id = a.id
        },
        url: function(a){
            var b = {
                read: "getStreamKeyFromSongIDEx",
                downloaded: "markSongDownloadedEx",
                "30sec": "markStreamKeyOver30Seconds",
                played: "markSongQueueSongPlayed",
                completed: "markSongComplete"
            };
            return b[a]
        },
        fetch: function(a){
            var b = this;
            return a = a || {}, a.parameters = {
                prefetch: !1,
                mobile: !1,
                songID: this.id
            }, a.success = function(c, d, e){
                if (!b.set(b.parse(c, e), a)) 
                    return !1
            }, Backbone.sync.call(this, "read", this, a)
        },
        mark: function(a){
            var b = this;
            return a = a || {}, a.parameters = {
                streamKey: b.get("streamKey"),
                streamServerID: b.get("streamServerID"),
                songID: b.id
            }, a.method == "played" && (a.parameters.songQueueID = 0, a.parameters.songQueueSongID = 0), Backbone.sync.call(this, a.method, this, a)
        },
        parse: function(a){
            return a.url = f(a.ip, a.streamKey), a
        }
    });
    a.GS.models.Songs = d, a.GS.models.Song = c
}(this), window.GS.models = window.GS.models || {}, function(a, b){
    var c = Backbone.Collection.extend({
        model: d,
        url: function(){
            return "getArtistsForTagRadio"
        }
    }), d = Backbone.Model.extend({
        initialize: function(a){
            this.id = a.ArtistID
        }
    }), e = Backbone.Model.extend({
        url: function(a){
            var b = {
                read: "getAutoplaySong",
                start: "startAutoplayTag"
            };
            return b[a]
        },
        start: function(){
            this.bind("change", this.gotSong, this), this.bind("readytoplay", this.readyToPlay, this), this.stop({
                silent: !0
            }), GS.views.audio.bind("player:beforeend", this.fetch, this), GS.views.audio.bind("player:ended", this.play, this), this.fetch({
                play: !0
            })
        },
        stop: function(a){
            a = a || {}, GS.views.audio.audio.pause(), GS.views.audio.unbind("player:beforeend", this.fetch), GS.views.audio.unbind("player:ended", this.play), this.collection.playing(null), a.silent || this.trigger("stopped")
        },
        play: function(a){
            a = a || {}, a.model === this.nextSong ? this.fetch({
                play: !0
            }) : (GS.views.audio.setModel(this.nextSong), GS.views.audio.play())
        },
        readyToPlay: function(){
            this.collection.playing(this), this._immediatePlay && (this.play(), this._immediatePlay = !1)
        },
        fetch: function(a){
            var b = this;
            return a = a || {}, this.nextSong ? (method = "read", a.parameters = {
                autoplayState: this.toJSON()
            }) : (method = "start", a.parameters = {
                tagID: this.id
            }), this._immediatePlay = a.play || !1, a.success = function(a, c, d){
                if (!a) {
                    b.trigger("error", b, a, d);
                    return
                }
                if (!b.set(b.parse(a, d))) 
                    return !1
            }, Backbone.sync.call(this, method, this, a)
        },
        gotSong: function(){
            this.nextSong.stream().fetch(), this.nextSong.stream().bind("change", function(){
                this.trigger("readytoplay")
            }, this)
        },
        parse: function(a){
            return this.nextSong = new GS.models.Song(a.nextSong), a.autoplayState
        }
    }), f = Backbone.Collection.extend({
        model: e,
        playing: function(a){
            return typeof a != "undefined" && (this._active = a), this._active || !1
        }
    }), g = new f([{
        id: 136,
        title: "Indie"
    }, {
        id: 67,
        title: "Electronica"
    }, {
        id: 750,
        title: "Classical"
    }, {
        id: 56,
        title: "Pop"
    }, {
        id: 3,
        title: "Rap"
    }, {
        id: 80,
        title: "Country"
    }, {
        id: 13,
        title: "Alternative"
    }, {
        id: 29,
        title: "Hip Hop"
    }, {
        id: 3529,
        title: "Classic Rock"
    }, {
        id: 75,
        title: "Ambient"
    }, {
        id: 111,
        title: "Punk"
    }, {
        id: 9,
        title: "90's Alt Rock"
    }, {
        id: 230,
        title: "Blues"
    }, {
        id: 12,
        title: "Rock"
    }, {
        id: 43,
        title: "Jazz"
    }, {
        id: 4,
        title: "R&B"
    }, {
        id: 122,
        title: "Folk"
    }, {
        id: 2563,
        title: "Dubstep"
    }, {
        id: 55,
        title: "80's"
    }, {
        id: 69,
        title: "Trance"
    }, {
        id: 96,
        title: "Bluegrass"
    }, {
        id: 160,
        title: "Reggae"
    }, {
        id: 17,
        title: "Metal"
    }, {
        id: 102,
        title: "Oldies"
    }, {
        id: 191,
        title: "Experimental"
    }, {
        id: 528,
        title: "Latin"
    }]);
    a.GS.models.stations = g
}(this), window.GS.models = window.GS.models || {}, function(a, b){
    var c = GS.models.Songs.extend({
        url: function(){
            return "popularGetSongs"
        },
        parse: function(a){
            return a.Songs
        }
    });
    a.GS.models.popular = new c
}(this), window.GS.models = window.GS.models || {}, function(a, b){
    var c = GS.models.Songs.extend({
        url: function(){
            return "getResultsFromSearch"
        },
        parse: function(a){
            return a.result
        }
    });
    a.GS.models.Search = c
}(this), window.GS.views = window.GS.views || {}, function(a, b){
    var c = Backbone.View.extend({
        el: $("#app"),
        render: function(a){
            this.destroy(this.active), this.active = a, this.el.append(this.active.el), this.trigger("page:navigated", this.active.navItem);
            var b = document.location.pathname + document.location.search + document.location.hash;
            _gaq.push(["_trackPageview", b])
        },
        destroy: function(a){
            if (!a) 
                return;
            a.unbind(), a.remove(), GS.views.terms.hide()
        },
        events: {
            "submit form": "submit"
        },
        submit: function(a){
            a.preventDefault()
        }
    }), d = Backbone.View.extend({
        el: $("#nav-container"),
        initialize: function(){
            GS.views.page.bind("page:navigated", this.markActive, this)
        },
        markActive: function(a){
            var b = this.$("#nav-" + a);
            this.active && this.active.removeClass("nav-item-selected"), this.active = b.addClass("nav-item-selected")
        }
    }), e = Backbone.View.extend({
        el: $("#loading"),
        template: _.compile("_spinner_message"),
        message: function(a){
            this.messageEl && this.messageEl.remove(), this.messageEl = $(this.template({
                message: a
            })), this.el.append(this.messageEl)
        },
        show: function(a){
            a && this.message(a), this.el.parent().addClass("shown")
        },
        hide: function(){
            this.el.parent().removeClass("shown")
        }
    }), f = Backbone.View.extend({
        el: "#wrapper",
        initialize: function(){
            this.body = $(document.body);
            if (a.iScroll) {
                var b = this;
                this.iScroll = new a.iScroll(this.el, {
                    hScroll: !1,
                    onScrollEnd: function(){
                        this.y === this.maxScrollY && b.trigger("scroller:scrolled-bottom", this)
                    }
                }), this.bind("scroller:refresh", this.refresh, this), this.body.addClass("enable-addressbar-hide")
            }
            this.bind("scroller:refresh", this.hideAddressbar, this), GS.views.page.bind("page:navigated", this.hideAddressbar, this), a.addEventListener("orientationchange", _.bind(this.hideAddressbar, this)), this.bind("scroller:player", this.makeRoomForPlayer, this), this.bind("scroller:station", this.makeRoomForStation, this), this.bind("scroller:stationHide", this.removeRoomForStation, this), a.addEventListener("scroll", _.debounce(_.bind(this.onScroll, this), 250))
        },
        onScroll: function(){
            var b = document.body.scrollHeight, c = document.documentElement.clientHeight, d = a.pageYOffset;
            d + c + 5 >= b && this.trigger("scroller:scrolled-bottom", {
                noRefresh: !0
            })
        },
        refresh: function(){
            this.iScroll && _.defer(_.bind(this.iScroll.refresh, this.iScroll))
        },
        hideAddressbar: function(){
            _.defer(function(){
                a.scrollTo(0, 1)
            })
        },
        makeRoomForPlayer: function(){
            this.body.addClass("room-for-player"), this.refresh()
        },
        makeRoomForStation: function(){
            this.body.addClass("room-for-station"), this.refresh()
        },
        removeRoomForStation: function(){
            this.body.removeClass("room-for-station"), this.refresh()
        }
    }), g = Backbone.View.extend({
        tagName: "ul",
        className: "song-list",
        initialize: function(a){
            this._rendered = 0, this.collection = a.collection, this.template = _.compile("songrows"), this.loadingEl = $(_.compile("songrows-loading")()), $(this.el).append(this.loadingEl), this.render(), GS.views.scroller.bind("scroller:scrolled-bottom", this.render, this)
        },
        render: function(a){
            a = a || {};
            var b = this._rendered + g.nextFew;
            b >= this.collection.length && (b = this.collection.length, this.loadingEl.addClass("hidden"), GS.views.scroller.unbind("scroller:scrolled-bottom", this.render));
            var c = this.collection.toArray().slice(this._rendered, b);
            this.loadingEl.before(this.template({
                songs: c
            })), this._rendered += g.nextFew, a.noRefresh || GS.views.scroller.trigger("scroller:refresh")
        },
        events: {
            "click li.song-row": "play"
        },
        play: function(a){
            var b = $(a.currentTarget).data("song-id");
            b && GS.views.audio.load(this.collection.get(b))
        }
    }, {
        nextFew: 12
    }), h = Backbone.View.extend({
        el: $("#terms"),
        show: function(){
            this.el.show()
        },
        hide: function(){
            this.el.hide()
        }
    });
    a.GS.views.page = new c, a.GS.views.navigation = new d, a.GS.views.spinner = new e, a.GS.views.terms = new h, a.addEventListener("DOMContentLoaded", function(){
        a.GS.views.scroller = new f
    }), a.GS.views.SongList = g
}(this), function(a, b){
    var c = Backbone.View.extend({
        navItem: "search",
        templates: {
            index: _.compile("search/index"),
            no_results: _.compile("search/no_results")
        },
        form: function(a){
            $(this.el).html(this.templates.index({
                query: a || ""
            })), this.els = {
                q: this.$("form input[name=q]"),
                clear: this.$(".input-clear")
            }, GS.views.scroller.trigger("scroller:refresh")
        },
        initialize: function(a, b){
            this.form(b), a && (this.collection = a, this.collection.bind("reset", this.results, this), b && GS.views.spinner.show("Searching for " + b))
        },
        results: function(){
            GS.views.spinner.hide(), this.collection.length > 0 ? (this.list = new GS.views.SongList({
                collection: this.collection
            }), $(this.el).append(this.list.el)) : ($(this.el).append(this.templates.no_results()), GS.views.scroller.trigger("scroller:refresh"))
        },
        events: {
            "submit form": "submit",
            "touchstart .input-clear": "clear",
            "keyup input": "showClear",
            "click .input-reduce": "autoFocus"
        },
        submit: function(b){
            var c = this.els.q.val();
            if (c === "") 
                return;
            a.location.hash = "/search/" + encodeURI(c), b.preventDefault()
        },
        clear: function(a){
            this.els.q.val("").focus(), this.els.clear.addClass("hidden"), a.stopPropagation()
        },
        showClear: function(a){
            var b = this.els.q.val();
            this.els.clear.toggleClass("hidden", b === "")
        },
        autoFocus: function(a){
            $(a.target).hasClass("input-clear") || this.els.q.focus()
        }
    });
    a.GS.views.Search = c
}(this), function(a, b){
    var c = Backbone.View.extend({
        navItem: "popular",
        initialize: function(a){
            this.collection = a, this.collection.bind("reset", this.render, this), GS.views.spinner.show("Loading Popular songs")
        },
        render: function(){
            GS.views.spinner.hide(), this.list = new GS.views.SongList({
                collection: this.collection
            }), $(this.el).append(this.list.el)
        }
    });
    a.GS.views.Popular = c
}(this), function(a, b){
    var c = Backbone.View.extend({
        template: _.compile("stations/list"),
        navItem: "stations",
        initialize: function(a){
            this.collection = a, this.render()
        },
        render: function(){
            var a = GS.models.stations.sortBy(function(a){
                return a.get("title")
            });
            $(this.el).html(this.template({
                stations: a,
                active: this.collection.playing()
            })), GS.views.scroller.trigger("scroller:refresh")
        },
        start: function(a){
            this.station = this.collection.get(a), GS.views.spinner.show("Loading " + this.station.get("title") + " radio"), this.station.start(), GS.views.Radio.instance(this.station), this.station.bind("readytoplay", this.play, this), this.station.bind("error", this.error, this), GS.views.audio.activatePlayback()
        },
        play: function(){
            GS.views.spinner.hide(), this.stationEl.addClass("stationrow-playing")
        },
        error: function(){
            GS.views.spinner.hide(), alert("Something went wrong, please try another station")
        },
        events: {
            "click .stationrow": "click"
        },
        click: function(a){
            var b = $(a.currentTarget), c = $(this.el).find(".stationrow-playing");
            c.length ? b.hasClass("stationrow-playing") ? this.station.fetch({
                play: !0
            }) : c.length && c[0] !== b[0] && (c.removeClass("stationrow-playing"), this.stationEl = b, this.start(this.stationEl.data("station-id"))) : (this.stationEl = b, this.start(this.stationEl.data("station-id")))
        }
    });
    a.GS.views.StationsList = c
}(this), window.GS.views = window.GS.views || {}, function(a, b){
    var c = Backbone.View.extend({
        templates: {
            controls: _.compile("audio/controls")
        },
        el: $("#player"),
        initialize: function(){
            this.audio = document.createElement("audio"), this.audio.autoplay = "autoplay", this.audio.preload = "auto", this.audio.autobuffer = !1, this.audio.loop = !1, this.render(), this.audio.addEventListener("canplay", _.bind(function(a){
                this.loaded(), this.trigger("player:durationchange")
            }, this)), this.audio.addEventListener("playing", _.bind(function(a){
                this.loaded()
            }, this)), this.audio.addEventListener("durationchange", _.bind(function(){
                this.trigger("player:durationchange")
            }, this)), this.audio.addEventListener("timeupdate", _.bind(this.timeUpdate, this)), this.audio.addEventListener("ended", _.bind(function(){
                this.trigger("player:ended", {
                    model: this.model
                })
            }, this)), this.bind("player:durationchange", this.durationChanged), this.bind("player:30secpassed", function(){
                this.model.stream().mark({
                    method: "30sec"
                })
            }), this.bind("player:ended", function(){
                this.model.stream().mark({
                    method: "completed"
                })
            })
        },
        render: function(){
            this.el.append(this.audio)
        },
        setModel: function(a){
            this.model = a, this.controls()
        },
        getModel: function(){
            return this.model
        },
        load: function(a){
            var b = GS.models.stations.playing();
            b && b.stop(), this.setModel(a), this.model.stream().clear({
                silent: !0
            }), this.model.stream().unbind("change", this.play), this.model.stream().bind("change", this.play, this), this.model.stream().fetch(), this.activatePlayback()
        },
        activatePlayback: function(){
            $.os.ios && !this._wasActivated && (this.audio.play(), this._wasActivated = !0)
        },
        play: function(){
            this.isLoaded = !1, !this.audio.paused && !this.audio.ended && this.audio.pause(), this.trigger30secs = _.once(_.bind(this.trigger, this, "player:30secpassed", {
                model: this.model.toJSON()
            })), this.triggerBeforeEnd = _.once(_.bind(this.trigger, this, "player:beforeend")), this.audio.setAttribute("src", this.model.stream().get("url")), this.audio.play(), this.audio.load(), this.model.stream().mark({
                method: "downloaded"
            })
        },
        loaded: function(){
            if (this.isLoaded) 
                return;
            this.isLoaded = !0, GS.models.stations.playing() ? _gaq.push(["_trackEvent", "audio", "radio_play"]) : _gaq.push(["_trackEvent", "audio", "song_play"]), this.trigger("player:played", {
                song: this.model.toJSON()
            }), this.model.stream().mark({
                method: "played"
            }), this.controlsEl.removeClass("loading").addClass("playing")
        },
        durationChanged: function(){
            this.audio.duration && this.durationEl.html(_.prettyDuration(this.audio.duration))
        },
        controls: function(){
            this.controlsEl && this.controlsEl.remove(), this.controlsEl = $(this.templates.controls({
                song: this.model.toJSON(),
                statusClass: "loading"
            })), this.el.append(this.controlsEl), GS.views.scroller.trigger("scroller:player"), this.progressEl = this.controlsEl.find(".progress-value"), this.timerEl = this.controlsEl.find(".played"), this.durationEl = this.controlsEl.find(".total")
        },
        timeUpdate: _.throttle(function(){
            this.timerEl && (this.timerEl[0].innerHTML = _.prettyDuration(this.audio.currentTime));
            if (this.progressEl) {
                var a = this.audio.currentTime / this.audio.duration * 100;
                this.progressEl.css("width", a + "%")
            }
            this.audio.duration && this.lastDuration != this.audio.duration && (this.lastDuration = this.audio.duration, this.trigger("player:durationchange")), this.audio.duration && ~ ~ (this.audio.duration - this.audio.currentTime) < 30 && this.triggerBeforeEnd(), this.audio.currentTime && ~ ~ this.audio.currentTime > 30 && this.trigger30secs()
        }, 1e3),
        events: {
            "click #controls": "click"
        },
        click: function(a){
            if (!this.isLoaded) 
                return;
            this.audio.paused ? (this.audio.play(), this.controlsEl.removeClass("paused").addClass("playing")) : (this.audio.pause(), this.controlsEl.removeClass("playing").addClass("paused"))
        }
    }), d = Backbone.View.extend({
        el: $("#station-controls"),
        initialize: function(a){
            this.template = _.compile("stations/controls"), this.setModel(a)
        },
        setModel: function(a){
            this.model && (this.model.unbind("readytoplay", this.render), this.model.unbind("stopped", this.hide)), this.model = a, this.model.bind("readytoplay", this.render, this), this.model.bind("stopped", this.hide, this)
        },
        render: function(){
            this.el.html(this.template({
                station: this.model.toJSON()
            })), this.el.removeClass("hidden"), GS.views.scroller.trigger("scroller:station")
        },
        hide: function(){
            this.el.addClass("hidden"), GS.views.scroller.trigger("scroller:stationHide")
        },
        events: {
            "click .frown": "frown",
            "click .smile": "smile"
        },
        frown: function(a){
            this.model.fetch({
                play: !0
            })
        },
        smile: function(a){
            $(a.target).addClass("inactive")
        }
    }, {
        instance: function(){
            var a;
            return function(b){
                return a ? b && b !== a.model && a.setModel(b) : a = new this(b), a
            }
        }()
    });
    a.GS.views.audio = new c, a.GS.views.Radio = d
}(this), window.GS.views = window.GS.views || {}, function(a, b){
    var c = Backbone.View.extend({
        el: $("#ads"),
        template: _.compile("ads_iframe"),
        sessionStart: (new Date).getTime() / 1e3,
        count: {
            radios: 0
        },
        initialize: function(){
            GS.views.audio.bind("player:played", this.tick, this), GS.views.audio.bind("player:30secpassed", function(){
                GS.models.stations.playing() || this.show()
            }, this)
        },
        render: function(){
            this.iframe = $(this.template({
                width: c.dimensions[0],
                height: c.dimensions[1]
            })), this.iframe.bind("load", _.bind(this.onLoad, this))
        },
        show: function(a){
            this.iframe || this.render();
            var b = this.buildParams(a);
            this.iframe.attr("src", c.baseURL + "?" + b), this.iframe[0].parentNode !== this.el[0] && this.el.prepend(this.iframe)
        },
        onLoad: function(a){
            this.el.addClass("shown")
        },
        events: {
            click: "hide"
        },
        hide: function(){
            this.el.removeClass("shown")
        },
        tick: function(a){
            if (this.count.radios >= 4 + ~ ~ (Math.random(1) * 2)) {
                this.show(), this.count.radios = 0;
                return
            }
            GS.models.stations.playing() && this.count.radios++
        },
        buildParams: function(a){
            var b = ["w=" + c.dimensions[0], "h=" + c.dimensions[1], "p=default"], d = GS.views.audio.getModel();
            d && b.push("2=" + d.get("ArtistID")), b.push("3=" + ~ ~ ((new Date).getTime() / 1e3 - this.sessionStart)), Backbone.history.fragment == Backbone.history.options.root ? b.push("9=1") : b.push("9=0");
            var e = GS.models.stations.playing();
            return e && (b.push("12=1"), b.push("13=" + e.get("AutoplayTagID"))), b.push("testAds=1"), b.join("&")
        }
    }, {
        baseURL: "/dfp_ads.html",
        dimensions: [300, 250]
    });
    a.GS.views.ads = new c
}(this), function(a, b){
    var c = Backbone.Router.extend({
        routes: {
            "*actions": "show"
        },
        show: function(){
            i.show(), GS.views.terms.show()
        }
    }), d = Backbone.Router.extend({
        routes: {
            "/stations": "list"
        },
        list: function(){
            GS.views.page.render(new GS.views.StationsList(GS.models.stations))
        }
    }), e = Backbone.Router.extend({
        routes: {
            "/search": "show",
            "/search/*query": "results"
        },
        show: function(){
            GS.views.page.render(new GS.views.Search)
        },
        results: function(a){
            var b = new GS.models.Search, c = new GS.views.Search(b, a);
            b.fetch({
                parameters: {
                    query: a,
                    type: "Songs",
                    guts: 1,
                    ppOverride: !0
                }
            }), GS.views.page.render(c)
        }
    }), f = Backbone.Router.extend({
        routes: {
            "/popular": "show"
        },
        show: function(){
            var a = new GS.views.Popular(GS.models.popular);
            GS.models.popular.fetch({
                parameters: {
                    type: "daily"
                }
            }), GS.views.page.render(a)
        }
    }), g = new c, h = new d, i = new e, j = new f
}(this), window.GS = window.GS || {}, function(a, b){
    a.addEventListener("DOMContentLoaded", function(){
        Backbone.history.start()
    }, !1), a.addEventListener("load", function(){
        GS.views.scroller.hideAddressbar()
    })
}(this)
